#include <stdio.h>
#include <string.h>
#include "../../CString.h"

#ifndef TEST_STD_STRING
  #define TEST_STD_STRING 0
#else
  #undef TEST_STD_STRING
  #define TEST_STD_STRING 1

  #include <string>
#endif


#if TEST_STD_STRING
  #define TEST_TYPE          std::string
  #define TEST_NULL          0
  #define TEST_OUT_OF_BOUNDS 0
#else
  #define TEST_TYPE          CString
  #define TEST_NULL          1
  #define TEST_OUT_OF_BOUNDS 1
#endif

#define MY_ASSERT(a) {if((a)) {++errors; printf("\n%4d: %25s: %s", __LINE__, name, #a);}}
#define CHAR_TEST(b, c)                                 \
{                                                       \
  MY_ASSERT(str[b] != (c))                              \
  MY_ASSERT(str.c_str()[b] != (c))                      \
  MY_ASSERT(((const TEST_TYPE &)str).c_str()[b] != (c)) \
  MY_ASSERT(str.at(b) != (c))                           \
  MY_ASSERT(((const TEST_TYPE &)str).at(b) != (c))      \
}

#define STRING_TEST(a)                   \
{                                        \
  if(!(a))                               \
  {                                      \
    MY_ASSERT(str.length() != 0)         \
    MY_ASSERT(str.size() != 0)           \
    if(TEST_NULL)                        \
      CHAR_TEST(0, 0)                    \
  }                                      \
  else                                   \
  {                                      \
    int n = (int)(strlen(a) + 1);        \
    int i;                               \
                                         \
    MY_ASSERT((int)str.length() != n - 1)\
    MY_ASSERT((int)str.size() != n - 1)  \
                                         \
    if(!(TEST_NULL))                     \
      --n;                               \
    for(i = 0; i < n; ++i)               \
      CHAR_TEST(i, ((char *)(a))[i])     \
  }                                      \
}

int ReplaceTest(void);
int CopyTest(void);
int OperatorPlusTest(void);
int SubStrTest(void);
int SwapTest(void);
int EraseTest(void);
int CompTest(void);
int FindLastNotOfTest(void);
int FindFirstNotOfTest(void);
int FindLastOfTest(void);
int FindFirstOfTest(void);
int RFindTest(void);
int FindTest(void);
int AssignTest(void);
int PushBackTest(void);
int AppendTest(void);
int ClearEmptyTest(void);
int ResizeTest(void);
int ConstructorTest(void);
int EqualTest(void);

int main(void)
{
  int errors = 0;

  errors += ConstructorTest();
  errors += EqualTest();
  errors += ResizeTest();
  errors += ClearEmptyTest();
  errors += AppendTest();
  errors += PushBackTest();
  errors += AssignTest();
  errors += FindTest();
  errors += RFindTest();
  errors += FindFirstOfTest();
  errors += FindLastOfTest();
  errors += FindFirstNotOfTest();
  errors += FindLastNotOfTest();
  errors += CompTest();
  errors += EraseTest();
  errors += SwapTest();
  errors += SubStrTest();
  errors += OperatorPlusTest();
  errors += CopyTest();
  errors += ReplaceTest();

  if(errors)
    printf("\n\nFailed %d tests\n", errors);
  return 0;
}

int FrameWork(void)
{
  const char *test_name = "";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "";
    TEST_TYPE str;
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}


int ReplaceTest(void)
{
  const char *test_name = "Replace Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "CString.replace(CString)";
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(0, (unsigned int)~0, rep);
      STRING_TEST("0123456789");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(0, 2, rep);
      STRING_TEST("0123456789df foo bar");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(1, (unsigned int)~0, rep);
      STRING_TEST("a0123456789");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(1, 5, rep);
      STRING_TEST("a0123456789oo bar");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 5, rep);
      STRING_TEST("asdf foo b0123456789");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 2, rep);
      STRING_TEST("asdf foo b0123456789");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 1, rep);
      STRING_TEST("asdf foo b0123456789r");
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 0, rep);
      STRING_TEST("asdf foo b0123456789ar");
    }
  }

  {
    const char *name = "replace(Sub CString)";
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 0,  0, rep,  0,  0);
      STRING_TEST("asdf foo bar")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 0, 3, rep,  0,  0);
      STRING_TEST("f foo bar")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 3, 10, rep,  0,  0);
      STRING_TEST("asd")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 0,  0, rep,  0, 15);
      STRING_TEST("0123456789asdf foo bar")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 0,  3, rep,  1, 15);
      STRING_TEST("123456789f foo bar")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 4, 10, rep,  1,  3);
      STRING_TEST("asdf123")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 10, rep,  1,  5);
      STRING_TEST("asdf foo12345")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 8,  4, rep,  1,  5);
      STRING_TEST("asdf foo12345")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 10, rep,  1,  4);
      STRING_TEST("asdf foo1234")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 10, rep,  1,  3);
      STRING_TEST("asdf foo123")
    }
    {
      TEST_TYPE rep("0123456789");
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 3, rep,  1,  4);
      STRING_TEST("asdf foo1234r")
    }
  }




  {
    const char *name = "CString.replace(char *)";
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0, (unsigned int)~0, "0123456789");
      STRING_TEST("0123456789");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0, 2, "0123456789");
      STRING_TEST("0123456789df foo bar");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(1, (unsigned int)~0, "0123456789");
      STRING_TEST("a0123456789");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(1, 5, "0123456789");
      STRING_TEST("a0123456789oo bar");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 5, "0123456789");
      STRING_TEST("asdf foo b0123456789");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 2, "0123456789");
      STRING_TEST("asdf foo b0123456789");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 1, "0123456789");
      STRING_TEST("asdf foo b0123456789r");
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 0, "0123456789");
      STRING_TEST("asdf foo b0123456789ar");
    }
  }

  {
    const char *name = "replace(Sub char *)";
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 0,  0, "0123456789" + 0,  0);
      STRING_TEST("asdf foo bar")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 0, 3, "0123456789" + 0,  0);
      STRING_TEST("f foo bar")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 3, 10, "0123456789" + 0,  0);
      STRING_TEST("asd")
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 0,  0, "0123456789" + 0, 15);
      STRING_TEST("0123456789asdf foo bar")
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 0,  3, "0123456789" + 1, 15);
      STRING_TEST("123456789f foo bar")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 4, 10, "0123456789" + 1,  3);
      STRING_TEST("asdf123")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 10, "0123456789" + 1,  5);
      STRING_TEST("asdf foo12345")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 8,  4, "0123456789" + 1,  5);
      STRING_TEST("asdf foo12345")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 10, "0123456789" + 1,  4);
      STRING_TEST("asdf foo1234")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 10, "0123456789" + 1,  3);
      STRING_TEST("asdf foo123")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace( 8, 3, "0123456789" + 1,  4);
      STRING_TEST("asdf foo1234r")
    }
  }


  {
    const char *name = "replace(char)";
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0, 20, 0, 'q');
      STRING_TEST("")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0, 20, 1, 'q');
      STRING_TEST("q")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0, 20, 2, 'q');
      STRING_TEST("qq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0, 20, 3, 'q');
      STRING_TEST("qqq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0,  1, 9, 'q');
      STRING_TEST("qqqqqqqqqsdf foo bar")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(0,  3, 3, 'q');
      STRING_TEST("qqqf foo bar")
    }

    {
      TEST_TYPE str("asdf foo bar");
      str.replace(4, 20, 0, 'q');
      STRING_TEST("asdf")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(4, 20, 1, 'q');
      STRING_TEST("asdfq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(4, 20, 2, 'q');
      STRING_TEST("asdfqq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(4, 20, 3, 'q');
      STRING_TEST("asdfqqq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(4,  1, 9, 'q');
      STRING_TEST("asdfqqqqqqqqqfoo bar")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(4,  3, 3, 'q');
      STRING_TEST("asdfqqqo bar")
    }



    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 20, 0, 'q');
      STRING_TEST("asdf foo b")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 20, 1, 'q');
      STRING_TEST("asdf foo bq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 20, 2, 'q');
      STRING_TEST("asdf foo bqq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10, 20, 3, 'q');
      STRING_TEST("asdf foo bqqq")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10,  1, 9, 'q');
      STRING_TEST("asdf foo bqqqqqqqqqr")
    }
    {
      TEST_TYPE str("asdf foo bar");
      str.replace(10,  3, 3, 'q');
      STRING_TEST("asdf foo bqqq")
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int CopyTest(void)
{
  const char *test_name = "Copy Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "copy()";
    char  buffer[10];
    TEST_TYPE str("foobar");
    memset(buffer, 0, 10); str.copy(buffer, 3);
    MY_ASSERT(strcmp(buffer, "foo"))
    memset(buffer, 0, 10); str.copy(buffer, 3, 3);
    MY_ASSERT(strcmp(buffer, "bar"))
    memset(buffer, 0, 10); str.copy(buffer, 3, 4);
    MY_ASSERT(strcmp(buffer, "ar"))
    memset(buffer, 0, 10); str.copy(buffer, 7, 4);
    MY_ASSERT(strcmp(buffer, "ar"))
    memset(buffer, 0, 10); str.copy(buffer, 3, 1);
    MY_ASSERT(strcmp(buffer, "oob"))
    memset(buffer, 0, 10); str.copy(buffer, 1000);
    MY_ASSERT(strcmp(buffer, "foobar"))
    memset(buffer, 0, 10); str.copy(buffer, (unsigned int)~0);
    MY_ASSERT(strcmp(buffer, "foobar"))
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int OperatorPlusTest(void)
{
  const char *test_name = "Operator+ Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "operator+";

    TEST_TYPE str2("bar");
    TEST_TYPE str("foo");

    MY_ASSERT((str   +  str2 == "foobar") == 0)
    MY_ASSERT(("foo" +  str2 == "foobar") == 0)
    MY_ASSERT(('f'   +  str2 == "fbar")   == 0)
    MY_ASSERT((str   + "bar" == "foobar") == 0)
    MY_ASSERT((str   +   'b' == "foob")   == 0)
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}


int SubStrTest(void)
{
  const char *test_name = "Sub String Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "";
    {
      TEST_TYPE str2("foobar");
      TEST_TYPE str = str2.substr();
      STRING_TEST("foobar")
    }
    {
      TEST_TYPE str2("foobar");
      TEST_TYPE str = str2.substr(1, 1);
      STRING_TEST("o")
    }
    {
      TEST_TYPE str2("foobar");
      TEST_TYPE str = str2.substr(0, 3);
      STRING_TEST("foo")
    }
    {
      TEST_TYPE str2("foobar");
      TEST_TYPE str = str2.substr(3, 3);
      STRING_TEST("bar")
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int SwapTest(void)
{
  const char *test_name = "Swap Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "";
    TEST_TYPE str2("bar");
    TEST_TYPE str("foo");
    str.swap(str2);
    STRING_TEST("bar");
    str2.swap(str);
    STRING_TEST("foo");
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}


int EraseTest(void)
{
  const char *test_name = "Erase Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "CString.erase()";
    {
      TEST_TYPE str("foobar");
      str.erase(0, 3);
      STRING_TEST("bar")
    }
    {
      TEST_TYPE str("foobar");
      str.erase(1, 3);
      STRING_TEST("far")
    }
    {
      TEST_TYPE str("foobar");
      str.erase(0, 10);
      STRING_TEST("")
    }
    {
      TEST_TYPE str("foobar");
      str.erase(3, 0);
      STRING_TEST("foobar")
    }
    {
      TEST_TYPE str("foobar");
      str.erase(5, 1);
      STRING_TEST("fooba")
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int CompTest(void)
{
  const char *test_name = "Comparison Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "CString.compare(CString)";
    {
      TEST_TYPE str2("asdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.compare(str2) != 0)
      str2 += 'a';
      MY_ASSERT(str.compare(str2) == 0)
      str += "aa";
      MY_ASSERT(str.compare(str2) == 0)
    }
    {
      TEST_TYPE str2("asdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.compare(0, 1, str2) == 0)
      MY_ASSERT(str.compare(1, 1, str2) == 0)
      MY_ASSERT(str.compare(0, 1, str2, 0, 1) != 0)
      MY_ASSERT(str.compare(0, 1, str2, 1, 1) == 0)
      MY_ASSERT(str.compare(0, 1, str2, 1, 0) == 0)
      MY_ASSERT(str.compare(0, 0, str2, 1, 1) == 0)
      if(TEST_OUT_OF_BOUNDS)
        MY_ASSERT(str.compare(0, 1, str2, 9, 1) == 0)
      if(TEST_OUT_OF_BOUNDS)
        MY_ASSERT(str.compare(9, 1, str2, 1, 1) == 0)
    }
  }

  {
    const char *name = "CString.compare(char *)";
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.compare("asdf") != 0)
      MY_ASSERT(str.compare("asdfa") == 0)
      str += "aa";
      MY_ASSERT(str.compare("asdfa") == 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.compare(0, 1, "asdf") == 0)
      MY_ASSERT(str.compare(1, 1, "asdf") == 0)
      MY_ASSERT(str.compare(0, 1, "asdf", 0, 1) != 0)
      MY_ASSERT(str.compare(0, 1, "asdf", 1, 1) == 0)
      MY_ASSERT(str.compare(0, 1, "asdf", 1, 0) == 0)
      MY_ASSERT(str.compare(0, 0, "asdf", 1, 1) == 0)
      if(TEST_OUT_OF_BOUNDS)
        MY_ASSERT(str.compare(0, 1, "asdf", 9, 1) == 0)
      if(TEST_OUT_OF_BOUNDS)
        MY_ASSERT(str.compare(9, 1, "asdf", 1, 1) == 0)
    }
  }

  {
    const char *name = "operators";
    TEST_TYPE str("a");
    TEST_TYPE str2("b");

    MY_ASSERT((str == str2) != 0)
    MY_ASSERT((str != str2) == 0)
    MY_ASSERT((str <  str2) == 0)
    MY_ASSERT((str >  str2) != 0)
    MY_ASSERT((str <= str2) == 0)
    MY_ASSERT((str >= str2) != 0)

    MY_ASSERT(("a" == str2) != 0)
    MY_ASSERT(("a" != str2) == 0)
    MY_ASSERT(("a" <  str2) == 0)
    MY_ASSERT(("a" >  str2) != 0)
    MY_ASSERT(("a" <= str2) == 0)
    MY_ASSERT(("a" >= str2) != 0)

    MY_ASSERT((str ==  "b") != 0)
    MY_ASSERT((str !=  "b") == 0)
    MY_ASSERT((str <   "b") == 0)
    MY_ASSERT((str >   "b") != 0)
    MY_ASSERT((str <=  "b") == 0)
    MY_ASSERT((str >=  "b") != 0)
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}


int FindLastNotOfTest(void)
{
  const char *test_name = "find_last_not_of Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "find_last_not_of(CString)";
    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search) != 5)
    }
    {
      TEST_TYPE search("sa");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search) != 7)
    }
    {
      TEST_TYPE search("sdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of(search) != 0)
    }
    {
      TEST_TYPE search("asdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of(search) != (unsigned int)~0)
    }

    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search, 3) != 1)
    }
    {
      TEST_TYPE search("f");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search, 2) != 2)
    }
    {
      TEST_TYPE search("qa");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search, 2) != 2)
    }
    {
      TEST_TYPE search("qa");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search, 0) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("en");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of(search, 12) != 7)
    }
  }

  {
    const char *name = "find_last_not_of(char *)";
    {
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of("df") != 5)
    }
    {
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of("sa") != 7)
    }
    {
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_not_of("sdf") != 4)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("asdf") != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("asd", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("df", 2) != 1)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("sd", 2) != 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("", 0) != 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("asdf", 12) != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("sd", 3, 2) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("fd", 3, 1) != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("d", 2, 1) != 1)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("qa", 2, 0) != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("aq", 0, 1) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_not_of("asdf", 12, 42) != (unsigned int)~0)
    }
  }

  {
    const char *name = "find_last_not_of(char)";
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_not_of('f') != 6)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_not_of('d') != 7)
    }

    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_not_of('f', 3) != 3)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_not_of('d', 6) != 5)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_not_of('d', 1) != 0)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_not_of('a', 3) != 2)
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int FindFirstNotOfTest(void)
{
  const char *test_name = "find_first_not_of Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "find_first_not_of(CString)";
    {
      TEST_TYPE search("as");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search) != 2)
    }
    {
      TEST_TYPE search("asd");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search) != 3)
    }
    {
      TEST_TYPE search("sd");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search) != 0)
    }
    {
      TEST_TYPE search("asdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search) != (unsigned int)~0)
    }

    {
      TEST_TYPE search("as");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 1) != 2)
    }
    {
      TEST_TYPE search("asd");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 1) != 3)
    }
    {
      TEST_TYPE search("sd");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 1) != 3)
    }
    {
      TEST_TYPE search("asdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 1) != (unsigned int)~0)
    }


    {
      TEST_TYPE search("as");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 3) != 3)
    }
    {
      TEST_TYPE search("asd");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 3) != 3)
    }
    {
      TEST_TYPE search("sd");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 3) != 3)
    }
    {
      TEST_TYPE search("asdf");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(search, 3) != (unsigned int)~0)
    }
  }

  {
    const char *name = "find_first_not_of(char *)";
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("as") != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asd") != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("sd") != 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asdf") != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("as", 1) != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asd", 1) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("sd", 1) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asdf", 1) != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("as", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asd", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("sd", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asdf", 3) != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("as", 3, 1) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asd", 3, 2) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("sd", 3, 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("sd", 3, 0) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of("asdf", 3, 0) != 3)
    }
  }

  {
    const char *name = "find_first_not_of(char)";
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of('a') != 1)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of('f') != 0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of('d', 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of('f', 3) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of(' ', 2) != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_not_of('a', 5) != (unsigned int)~0)
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int FindLastOfTest(void)
{
  const char *test_name = "find_last_of Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "find_last_of(CString)";
    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search) != 7)
    }
    {
      TEST_TYPE search("sa");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search) != 5)
    }
    {
      TEST_TYPE search("qa");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of(search) != 0)
    }
    {
      TEST_TYPE search("en");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of(search) != (unsigned int)~0)
    }

    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search, 3) != 3)
    }
    {
      TEST_TYPE search("f");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search, 2) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("qa");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search, 2) != 0)
    }
    {
      TEST_TYPE search("qa");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search, 0) != 0)
    }
    {
      TEST_TYPE search("en");
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of(search, 12) != (unsigned int)~0)
    }
  }

  {
    const char *name = "find_last_of(char *)";
    {
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of("df") != 7)
    }
    {
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of("sa") != 5)
    }
    {
      TEST_TYPE str("asdfasdf");
      MY_ASSERT(str.find_last_of("qa") != 4)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("en") != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("df", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("f", 2) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("qa", 2) != 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("qa", 0) != 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("en", 12) != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("df", 3, 2) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("df", 3, 1) != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("f", 2, 1) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("qa", 2, 0) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("qa", 0, 1) != (unsigned int)~0)
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_last_of("en", 12, 42) != (unsigned int)~0)
    }
  }

  {
    const char *name = "find_last_of(char)";
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('f') != 7)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('d') != 6)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('s') != 5)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('a') != 4)
    }

    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('f', 3) != 0)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('d', 6) != 6)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('s', 1) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("fdsaasdf");
      MY_ASSERT(str.find_last_of('a', 3) != 3)
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int FindFirstOfTest(void)
{
  const char *test_name = "find_first_of Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "find_first_of(CString)";
    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search) != 2)
    }
    {
      TEST_TYPE search("ef");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search) != 3)
    }
    {
      TEST_TYPE search("af");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search) != 0)
    }
    {
      TEST_TYPE search(" ");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search) != (unsigned int)~0)
    }

    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 1) != 2)
    }
    {
      TEST_TYPE search("ef");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 1) != 3)
    }
    {
      TEST_TYPE search("af");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 1) != 3)
    }
    {
      TEST_TYPE search(" ");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 1) != (unsigned int)~0)
    }


    {
      TEST_TYPE search("df");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 3) != 3)
    }
    {
      TEST_TYPE search("ef");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 3) != 3)
    }
    {
      TEST_TYPE search("af");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 3) != 3)
    }
    {
      TEST_TYPE search(" ");
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(search, 3) != (unsigned int)~0)
    }
  }

  {
    const char *name = "find_first_of(char *)";
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("df") != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("ef") != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("af") != 0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(" ") != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("df", 1) != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("ef", 1) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("af", 1) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(" ", 1) != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("df", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("ef", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("af", 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(" ", 3) != (unsigned int)~0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("df", 3, 1) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("ef", 3, 2) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("af", 3, 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of("af", 3, 0) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(" ", 3, 0) != (unsigned int)~0)
    }
  }

  {
    const char *name = "find_first_of(char)";
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of('d') != 2)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of('f') != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(' ') != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of('a') != 0)
    }

    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of('d', 3) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of('f', 3) != 3)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of(' ', 2) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf");
      MY_ASSERT(str.find_first_of('a', 5) != (unsigned int)~0)
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int RFindTest(void)
{
  const char *test_name = "Reverse Find Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "rfind(CString)";
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind(search) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind(search) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar fooba ");
      MY_ASSERT(str.rfind(search) != 12)
    }

    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind(search, 25) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind(search, 24) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind(search, 23) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind(search, 25) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind(search, 24) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind(search, 23) != 19)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 25) != 12)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 24) != 12)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 23) != 12)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 17) != 12)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 16) != 12)
    }
    {
      TEST_TYPE search("asdf");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search) != 0)
    }
    {
      TEST_TYPE search("asdf");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 16) != 0)
    }
    {
      TEST_TYPE search("fdsa");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("fdsa");
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind(search, 16) != (unsigned int)~0)
    }
  }

  {
    const char *name = "rfind(CString)";
    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar") != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind("foobar") != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba ");
      MY_ASSERT(str.rfind("foobar") != 12)
    }

    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar", 25) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar", 24) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar", 23) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar", 22) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar", 19) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar ");
      MY_ASSERT(str.rfind("foobar", 18) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind("foobar", 25) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind("foobar", 24) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind("foobar", 23) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind("foobar", 19) != 19)
    }
    {
      TEST_TYPE str("asdf foobar foobar foobar");
      MY_ASSERT(str.rfind("foobar", 18) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 25) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 24) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 23) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 17) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 16) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 12) != 12)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("foobar", 11) != 5)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("asdf") != 0)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("asdf", 16) != 0)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("fdsa") != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf foobar foobar fooba  ");
      MY_ASSERT(str.rfind("fdsa", 16) != (unsigned int)~0)
    }
  }

  {
    const char *name = "rfind(char)";
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind(' ') != 12);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind(' ', 12) != 12);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind(' ', 11) != 8);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind(' ', 8) != 8);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind(' ', 7) != 4);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind('a', 7) != 0);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind('q') != (unsigned int)~0);
    }
    {
      TEST_TYPE str("asdf foo bar ");
      MY_ASSERT(str.rfind('q', 7) != (unsigned int)~0);
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int FindTest(void)
{
  const char *test_name = "Find Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Append tests here
  {
    const char *name = "find(CString)";
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find(search) != 13)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find(search, 10) != 13)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find(search, 13) != 13)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find(search, 14) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find(search) != 13)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find(search, 10) != 13)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find(search, 13) != 13)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find(search, 14) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(search) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(search, 10) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(search, 13) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(search, 14) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("foobar");
      MY_ASSERT(str.find(search, 0) != 0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("fooba");
      MY_ASSERT(str.find(search, 0) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("foobar");
      TEST_TYPE str("fooba");
      MY_ASSERT(str.find(search, 13) != (unsigned int)~0)
    }
    {
      TEST_TYPE search("a");
      TEST_TYPE str("fooba");
      MY_ASSERT(str.find(search, 4) != 4)
    }
  }

  {
    const char *name = "find(char *)";
    {
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find("foobar", 0) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find("foobar", 14) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find("foobar", 0, 3) != 5)
    }
    {
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find("foobar", 0, 4) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find("foobar", 5, 3) != 5)
    }
    {
      TEST_TYPE str("asdf foo bar foobar ddd");
      MY_ASSERT(str.find("foobar", 6, 3) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find("foobar", 0) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find("foobar", 13) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find("foobar", 14) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf foo bar foobar");
      MY_ASSERT(str.find("foobar", 13, 3) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find("foobar", 0) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find("foobar", 0, 5) != 13)
    }
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find("foobar", 13) != (unsigned int)~0)
    }
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find("foobar", 13, 5) != 13)
    }
  }

  {
    const char *name = "find(char)";
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(' ') != 4);
    }
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(' ', 4) != 4);
    }
    {
      TEST_TYPE str("asdf foo bar fooba");
      MY_ASSERT(str.find(' ', 5) != 8);
    }
    {
      TEST_TYPE str("asdf ");
      MY_ASSERT(str.find(' ') != 4);
    }
    {
      TEST_TYPE str("asdf ");
      MY_ASSERT(str.find(' ', 4) != 4);
    }
    {
      TEST_TYPE str("asdf ");
      MY_ASSERT(str.find(' ', 5) != (unsigned int)~0);
    }
    {
      TEST_TYPE str("asdf ");
      MY_ASSERT(str.find('q') != (unsigned int)~0);
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int AssignTest(void)
{
  const char *test_name = "Assign Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "CString.assign(CString)";
    TEST_TYPE copy("bar");
    TEST_TYPE str("");
    str.assign(copy);
    STRING_TEST("bar")
  }
  if(TEST_NULL)
  {
    const char *name = "CString.assign(CString)";
    TEST_TYPE copy("bar");
    TEST_TYPE str(0);
    str.assign(copy);
    STRING_TEST("bar")
  }
  {
    const char *name = "CString.assign(CString)";
    TEST_TYPE copy("bar");
    TEST_TYPE str("foo");
    str.assign(copy);
    STRING_TEST("bar")
  }
  {
    const char *name = "CString.assign(Its Self)";
    TEST_TYPE str("foo");
    str.assign(str);
    STRING_TEST("foo")
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "CString.assign(Substring from CString)";
    char test [] = "asdf_foo_bar";
    char test2[] = "fdsa_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    start = 5;
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test[end];
        test[end] = 0;
      }

      TEST_TYPE str("asdf_");
      str.assign(copy, start, end - start);
      STRING_TEST(test + 5);

      if(end < n)
        test[end] = temp;
    }
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test2[end];
        test2[end] = 0;
      }

      TEST_TYPE str("fdsa_");
      str.assign(copy, start, end - start);
      STRING_TEST(test2 + 5);

      if(end < n)
        test2[end] = temp;
    }
      // Out of range
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str("foo");
      str.assign(copy, 3, 1);
      STRING_TEST("f")
    }
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str("foo");
      str.assign(copy, 4, 1);
      STRING_TEST("")
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str("foo");
      str.assign(copy, 5, 1);
      STRING_TEST("")
    }
  }
  {
    const char *name = "CString.assign(Substring of its self)";
    {
      TEST_TYPE str("asdf");
      str.assign(str, 0, 1);
      STRING_TEST("a");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str, 0, 2);
      STRING_TEST("as");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str, 1, 1);
      STRING_TEST("s");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str, 1, 2);
      STRING_TEST("sd");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str, 3, 6);
      STRING_TEST("f");
    }
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "CString.assign(Substring from char *)";
    char test [] = "asdf_foo_bar";
    char test2[] = "fdsa_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    start = 5;
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test[end];
        test[end] = 0;
      }

      if(TEST_OUT_OF_BOUNDS || end < n)
      {
        TEST_TYPE str("asdf_");
        str.assign(copy.c_str() + start, end - start);
        STRING_TEST(test + 5);
      }

      if(end < n)
        test[end] = temp;
    }
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test2[end];
        test2[end] = 0;
      }

      if(TEST_OUT_OF_BOUNDS || end < n)
      {
        TEST_TYPE str("fdsa_");
        str.assign(copy.c_str() + start, end - start);
        STRING_TEST(test2 + 5);
      }

      if(end < n)
        test2[end] = temp;
    }
  }
  {
    const char *name = "CString.assign(Substring of its c_str())";
    {
      TEST_TYPE str("asdf");
      str.assign(str.c_str() + 0, 1);
      STRING_TEST("a");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str.c_str() + 0, 2);
      STRING_TEST("as");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str.c_str() + 1, 1);
      STRING_TEST("s");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(str.c_str() + 1, 2);
      STRING_TEST("sd");
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("asdf");
      str.assign(str.c_str() + 3, 6);
      STRING_TEST("f");
    }

      // Out of range
    {
      TEST_TYPE str("foo");
      str.assign("asdf", 3, 1);
      STRING_TEST("f")
    }
    {
      TEST_TYPE str("foo");
      str.assign("asdf", 4, 1);
      STRING_TEST("")
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("foo");
      str.assign("asdf", 5, 1);
      STRING_TEST("")
    }
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "CString.assign(char *)";
    char test [] = "asdf_foo_bar";
    char test2[] = "fdsa_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    start = 5;
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test[end];
        test[end] = 0;
      }

      TEST_TYPE str("asdf_");
      str.assign(test + start);
      STRING_TEST(test + 5);

      if(end < n)
        test[end] = temp;
    }
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test2[end];
        test2[end] = 0;
      }

      TEST_TYPE str("fdsa_");
      str.assign(test2 + start);
      STRING_TEST(test2 + 5);

      if(end < n)
        test2[end] = temp;
    }
  }
  {
    const char *name = "CString.assign(padding)";
    {
      TEST_TYPE str("asdf");
      str.assign(0, 'a');
      STRING_TEST("");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(1, 'a');
      STRING_TEST("a");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(2, 'a');
      STRING_TEST("aa");
    }
    {
      TEST_TYPE str("asdf");
      str.assign(3, 'a');
      STRING_TEST("aaa");
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int PushBackTest(void)
{
  const char *test_name = "Push Back Test";
  int   errors    = 0;
  char  test[]    = "asdf_foobar";
  printf("%25s: ", test_name);

  {
    int start;
    int n;
    const char *name = "Push Back Test";
    TEST_TYPE str("asdf_");

    n = strlen(test);
    for(start = 5; start < n; ++start)
    {
      char temp;

      if(start + 1 < n)
      {
        temp = test[start + 1];
        test[start + 1] = 0;
      }

      str.push_back(test[start]);
      STRING_TEST(test);

      if(start + 1 < n)
        test[start + 1] = temp;
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int AppendTest(void)
{
  const char *test_name = "Append Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "CString += CString";
    TEST_TYPE copy("bar");
    TEST_TYPE str("foo");
    str += copy;
    STRING_TEST("foobar")
  }
  {
    const char *name = "CString += Its Self";
    TEST_TYPE str("foo");
    str += str;
    STRING_TEST("foofoo")
  }
  {
    const char *name = "CString += Its c_str()";
    TEST_TYPE str("foo");
    str += str.c_str();
    STRING_TEST("foofoo")
  }
  {
    const char *name = "CString += char *";
    char *copy = "bar";
    TEST_TYPE str("foo");
    str += copy;
    STRING_TEST("foobar")
  }
  {
    const char *name = "CString += char";
    char  copy = 'b';
    TEST_TYPE str("foo");
    str += copy;
    STRING_TEST("foob")
  }
  {
    const char *name = "CString.append(CString)";
    TEST_TYPE copy("bar");
    TEST_TYPE str("foo");
    str.append(copy);
    STRING_TEST("foobar")
  }
  {
    const char *name = "CString.append(Its Self)";
    TEST_TYPE str("foo");
    str.append(str);
    STRING_TEST("foofoo")
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "CString.append(Substring from CString)";
    char test [] = "asdf_foo_bar";
    char test2[] = "fdsa_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    start = 5;
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test[end];
        test[end] = 0;
      }

      TEST_TYPE str("asdf_");
      str.append(copy, start, end - start);
      STRING_TEST(test);

      if(end < n)
        test[end] = temp;
    }
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test2[end];
        test2[end] = 0;
      }

      TEST_TYPE str("fdsa_");
      str.append(copy, start, end - start);
      STRING_TEST(test2);

      if(end < n)
        test2[end] = temp;
    }

      // Out of range
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str("foo");
      str.append(copy, 3, 1);
      STRING_TEST("foof");
    }
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str("foo");
      str.append(copy, 4, 1);
      STRING_TEST("foo");
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str("foo");
      str.append(copy, 5, 1);
      STRING_TEST("foo");
    }
  }
  {
    const char *name = "CString.append(Substring of its self)";
    {
      TEST_TYPE str("asdf");
      str.append(str, 0, 1);
      STRING_TEST("asdfa");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str, 0, 2);
      STRING_TEST("asdfas");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str, 1, 1);
      STRING_TEST("asdfs");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str, 1, 2);
      STRING_TEST("asdfsd");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str, 3, 6);
      STRING_TEST("asdff");
    }
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "CString.append(Substring from char *)";
    char test [] = "asdf_foo_bar";
    char test2[] = "fdsa_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    start = 5;
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test[end];
        test[end] = 0;
      }

      if(TEST_OUT_OF_BOUNDS || end < n)
      {
        TEST_TYPE str("asdf_");
        str.append(copy.c_str() + start, end - start);
        STRING_TEST(test);
      }

      if(end < n)
        test[end] = temp;
    }
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test2[end];
        test2[end] = 0;
      }

      if(TEST_OUT_OF_BOUNDS || end < n)
      {
        TEST_TYPE str("fdsa_");
        str.append(copy.c_str() + start, end - start);
        STRING_TEST(test2);
      }

      if(end < n)
        test2[end] = temp;
    }
  }
  {
    const char *name = "CString.append(Substring of its c_str())";
    {
      TEST_TYPE str("asdf");
      str.append(str.c_str() + 0, 1);
      STRING_TEST("asdfa");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str.c_str() + 0, 2);
      STRING_TEST("asdfas");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str.c_str() + 1, 1);
      STRING_TEST("asdfs");
    }
    {
      TEST_TYPE str("asdf");
      str.append(str.c_str() + 1, 2);
      STRING_TEST("asdfsd");
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("asdf");
      str.append(str.c_str() + 3, 6);
      STRING_TEST("asdff");
    }
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "CString.append(char *)";
    char test [] = "asdf_foo_bar";
    char test2[] = "fdsa_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    start = 5;
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test[end];
        test[end] = 0;
      }

      TEST_TYPE str("asdf_");
      str.append(test + start);
      STRING_TEST(test);

      if(end < n)
        test[end] = temp;
    }
    for(end = n + 3; end-- > start;)
    {
      char temp;

      if(end < n)
      {
        temp = test2[end];
        test2[end] = 0;
      }

      TEST_TYPE str("fdsa_");
      str.append(test2 + start);
      STRING_TEST(test2);

      if(end < n)
        test2[end] = temp;
    }
  }
  {
    const char *name = "CString.append(padding)";
    {
      TEST_TYPE str("asdf");
      str.append(0, 'a');
      STRING_TEST("asdf");
    }
    {
      TEST_TYPE str("asdf");
      str.append(1, 'a');
      STRING_TEST("asdfa");
    }
    {
      TEST_TYPE str("asdf");
      str.append(2, 'a');
      STRING_TEST("asdfaa");
    }
    {
      TEST_TYPE str("asdf");
      str.append(3, 'a');
      STRING_TEST("asdfaaa");
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int ClearEmptyTest(void)
{
  const char *test_name = "Clear & Empty Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "Clear & Empty";
    {
      TEST_TYPE str("asdf");
      str.clear();
      STRING_TEST("")
      MY_ASSERT(!str.empty())
    }
    if(TEST_NULL)
    {
      TEST_TYPE str("asdf");
      str.clear();
      STRING_TEST(0)
      MY_ASSERT(!str.empty())
    }
    {
      TEST_TYPE str("");
      str.clear();
      STRING_TEST("")
      MY_ASSERT(!str.empty())
    }
    if(TEST_NULL)
    {
      TEST_TYPE str("");
      str.clear();
      STRING_TEST(0)
      MY_ASSERT(!str.empty())
    }
    if(TEST_NULL)
    {
      TEST_TYPE str(0);
      str.clear();
      STRING_TEST("")
      MY_ASSERT(!str.empty())
    }
    if(TEST_NULL)
    {
      TEST_TYPE str(0);
      str.clear();
      STRING_TEST(0)
      MY_ASSERT(!str.empty())
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int ResizeTest(void)
{
  const char *test_name = "Resize Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "Shrink";
    TEST_TYPE str("asdf");
    str.resize(2);
    STRING_TEST("as")
  }

  {
    const char *name = "No Change";
    TEST_TYPE str("asdf");
    str.resize(4);
    STRING_TEST("asdf")
  }

  {
    const char *name = "Grow";
    TEST_TYPE str("asdf");
    str.resize(7);
      // Can't use STRING_TEST, since this should append 0s
    MY_ASSERT(str.length() != 7)
    MY_ASSERT(str.size() != 7)
    CHAR_TEST(0, 'a')
    CHAR_TEST(1, 's')
    CHAR_TEST(2, 'd')
    CHAR_TEST(3, 'f')
    CHAR_TEST(4,  0 )
    CHAR_TEST(5,  0 )
    CHAR_TEST(6,  0 )
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int EqualTest(void)
{
  const char *test_name = "operator= Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  {
    const char *name = "CString = CString";
    TEST_TYPE copy("asdf");
    TEST_TYPE str;
    str = copy;
    STRING_TEST("asdf");
  }

  {
    const char *name = "CString = c string";
    TEST_TYPE str;
    str = "asdf";
    STRING_TEST("asdf");
  }

  {
    const char *name = "CString = char";
    TEST_TYPE str;
    str = 'c';
    STRING_TEST("c");
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}

int ConstructorTest(void)
{
  const char *test_name = "Constructor Test";
  int   errors    = 0;
  printf("%25s: ", test_name);

  // Default Constructor
  {
    TEST_TYPE str;
    const char *name = "Default CTor";
    MY_ASSERT(str.length() != 0)
    STRING_TEST(0)
  }

  // C String CTor
  {
    const char *name = "C String CTor";
    {
      TEST_TYPE str("asdf");
      STRING_TEST("asdf")
    }
    {
      TEST_TYPE str("");
      STRING_TEST("")
    }
    if(TEST_NULL)
    {
      TEST_TYPE str(0);
      STRING_TEST(0)
    }
  }

  // Sub C String CTor
  {
    const char *name = "Sub C String CTor";
    {
      TEST_TYPE str("asdf", 3);
      STRING_TEST("asd")
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("as", 3);
      STRING_TEST("as")
    }
    {
      TEST_TYPE str("asdf", 4);
      STRING_TEST("asdf")
    }
    if(TEST_OUT_OF_BOUNDS)
    {
      TEST_TYPE str("asdf", 6);
      STRING_TEST("asdf")
    }
  }

  // Copy CTor
  {
    const char *name = "Copy CTor";
    {
      TEST_TYPE copy("asdf");
      TEST_TYPE str(copy);
      STRING_TEST("asdf")
    }
    {
      TEST_TYPE copy("");
      TEST_TYPE str(copy);
      STRING_TEST("")
    }
    if(TEST_NULL)
    {
      TEST_TYPE copy(0);
      TEST_TYPE str(copy);
      STRING_TEST(0)
    }
  }

  // Copy SubString CTor
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "Copy SubString CTor";
    char test[] = "asdf_foo_bar";
    TEST_TYPE copy(test);

    n = strlen(test);
    for(start = 0; start < n; ++start)
      for(end = n + 3; end-- > start;)
      {
        char temp;

        if(end < n)
        {
          temp = test[end];
          test[end] = 0;
        }

        TEST_TYPE str(copy, start, end - start);
        STRING_TEST(test + start);

        if(end < n)
          test[end] = temp;
      }
  }
  {
    unsigned int n;
    unsigned int start, end;
    const char *name = "Copy SubString CTor";
    char test[] = "asdf_foo_bar";

    n = strlen(test);
    for(start = 0; start < n; ++start)
      for(end = n + 3; end-- > start;)
      {
        char temp;

        if(end < n)
        {
          temp = test[end];
          test[end] = 0;
        }

        if(TEST_OUT_OF_BOUNDS || end < n)
        {
          TEST_TYPE str(test + start, end - start);
          STRING_TEST(test + start);
        }

        if(end < n)
          test[end] = temp;
      }
  }

  // Padding CTor
  {
    const char *name = "Padding CTor";

    {
      TEST_TYPE str(0, 'a');
      STRING_TEST(0)
    }
    {
      TEST_TYPE str(1, 'a');
      STRING_TEST("a")
    }
    {
      TEST_TYPE str(2, 'a');
      STRING_TEST("aa")
    }
    {
      TEST_TYPE str(3, 'a');
      STRING_TEST("aaa")
    }
    {
      TEST_TYPE str(4, 'a');
      STRING_TEST("aaaa")
    }
  }

  if(!errors)
    printf("Passed\n");
  else
    printf("\n%25s: %d Tests Failed\n", test_name, errors);
  return errors;
}
